package com.altio.swing.portlet.util;

import java.awt.Point;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class ColumnList<T> {

  private List<List<T>> columns = new ArrayList<List<T>>();
  
  public ColumnList() {
    this(0);
  }
  
  public ColumnList(final int initialColumnCount) {
    fillListToSize(initialColumnCount);
  }
  
  private void fillListToSize(final int size) {
    int extraRequired = size - columns.size();
    for(int i = 0; i < extraRequired; i++) {
      columns.add(new ArrayList<T>());
    }
  }
  
  public int getColumnCount() {
    return columns.size();
  }
  
  public void appendToColumn(T toAdd, final int columnToAddTo) {
    remove(toAdd);
    fillListToSize(columnToAddTo + 1);
    columns.get(columnToAddTo).add(toAdd);
  }

  public void remove(T toRemove) {
    for (List<T> column : columns) {
      column.remove(toRemove);
    }
  }
  
  public int getElementCount() {
    int total = 0;
    for (List<T> column : columns) {
      total += column.size();
    }
    return total;
  }
  
  public List<T> getColumn(final int columnIndex) {
    if(columnIndex >= 0 && columnIndex < columns.size()) {
      return columns.get(columnIndex);
    } else {
      return null;
    }
  }
  
  public boolean contains(T element) {
    for (List<T> column : columns) {
      if(column.contains(element)) {
        return true;
      }
    }
    
    return false;
  }
  
  public Iterator<List<T>> columnIterator() {
    return columns.iterator();
  }
  
  public List<T> getColumns(final int columnIndex) {
    return columns.get(columnIndex);
  }
  
  protected List<T> getColumn(T toFind) {
    for(List<T> column : columns) {
      if(column.contains(toFind)) {
        return column;
      }
    }
    
    return null;
  }
  
  public boolean insertBefore(T toInsert, T before) {
    List<T> column = getColumn(before);
    
    if(column != null) {
    remove(toInsert);
     column.add(column.indexOf(before), toInsert) ;
     return true;
    } else {
      return false;
    }
  }
  
  public boolean insertAfter(T toInsert, T after) {
    List<T> column = getColumn(after);
    
    if(column != null) {
    remove(toInsert);
     column.add(column.indexOf(after) + 1, toInsert);
     return true;
    } else {
      return false;
    }
  }
  
  public void setPosition(final T toPosition, final Point position) {
    List<T> column = getColumn(position.x);
    
    if(position.y < 0 || column == null || position.y >= column.size()) {
      appendToColumn(toPosition, position.x);
    } else {
      column.add(position.y, toPosition);
    }
  }
  
  public Point getPosition(final T element) {
    List<T> column = getColumn(element);
    
    if(column != null) {
      return new Point(columns.indexOf(column), column.indexOf(element));
    } else {
      return null;
    }
  }
}